/* 
 * File:   ThreadMngEventRld.cpp
 * Author: batista
 * 
 * Created on 15 de Março de 2013, 09:06
 */

#include "ThreadMngEventRld.h"

ThreadMngEventRld::ThreadMngEventRld() : JoinableThread() {
    //    
    tmut = new TimeUtil();
    //
}

ThreadMngEventRld::~ThreadMngEventRld() {
}

/**
 * Metodo Chamador da Thread
 */
void ThreadMngEventRld::run() {
    vector<Event*> vec_events_to_work;
    //
    ShowMessage("ThreadMngEventRld()", COLOR_PINK, COLOR_GREEN);
    //
    ::sleep(3);    
    /* Pega o time-out para os atendimentos dos eventos */
    timeout_attend = dbconn->getTimeOutForAttend();
    // 
    //Loop infinito
    while (1) {
        //
        ShowMessage("(  PROCURANDO EVENTOS PARA APLICAR REGRAS )", COLOR_BLUE, COLOR_PINK);

        //Aguarda um segundo
        tmut->SleepSeg(100);
        //

        //Pega eventos disponiveis para trabalho
        vec_events_to_work = dbconn->getEventToWorkFromSqLite();

        /**
         * Se tiver eventos disponiveis na lista, 
         * entra para aplicar a regra de negocio. 
         */
        if (!vec_events_to_work.empty()) {
            event = new Event();
            //
            for (int i = 0; i < vec_events_to_work.size(); i++) {
                event = vec_events_to_work.at(i);
                //
                //Pesquisa ID para o evento da Rauland
                event = dbconn->getEventIDToEventRldInSqLite(event);

                ShowMessage("Evento ID: " + tmut->ConvIntToString(event->GetEventId()) + " : Mensagem: " + event->GetEventMessage(), COLOR_BLUE, COLOR_CIANO);

                //Se tem ID pega Ala
                if (event->GetEventId() > 0) {
                    event = dbconn->getWardIDToWardRldInSqLite(event);
                    ShowMessage("Ala ID: " + event->GetWardId() + " : Sigla: " + event->GetWardSigla(), COLOR_BLUE, COLOR_CIANO);
                }

                //Se pegou o ID da Ala, entra..
                if (!event->GetWardId().empty()) {
                    event = dbconn->getRoomIDToRoomRldInSqLite(event);
                    ShowMessage("Room ID: " + event->GetRoomId() + " : Nome: " + event->GetRoomSigla(), COLOR_BLUE, COLOR_GREEN);
                }

                //Se pegou o ID do Quarto, entra..
                if (!event->GetRoomId().empty()) {
                    //Aplica regra de negocio
                    //
                    runApplyRulesForProtocol(event);
                }

            }//fim for
        }//fim if

    }//fim while
    //
}

/**
 * Metodo responsavel por aplicar
 * a regra de negocio para o protolo
 * e adicionar na base de dados.
 */
void ThreadMngEventRld::runApplyRulesForProtocol(Event* nevent) {
    //
    std::string query, date_with_timeout, msg;
    event = new Event();
    //
    event = dbconn->getTypeEventRldToApplyRule(nevent);
    //
    ShowMessage("EVENTO PESQUISADO......: ID: "
            + tmut->ConvLongToString(event->GetPtlId()) + " DATA ENTRA: "
            + event->GetDate_Time_Entered() + " DATA SAIDA: "
            + event->GetDate_Time_Exited(), COLOR_BLUE, COLOR_PINK);
    //
    switch (getOptionForApply(event)) {
            /**
             * Se evente_rauland vim sem um id, e se o evento nao for 
             * de cancelamento, é porque não tem evento para
             * ser atendido, então entra para fazer a inclusão
             * @param event_rauland
             */
        case 1: // '\001'
            ShowMessage("ADD UM NOVO EVENTO!", COLOR_BLUE, COLOR_PINK);
            //
            query = "INSERT INTO data_protocol (ward_id, room_id, event_id, date_time_called, "
                    "bed_room_code) VALUES ('"
                    + nevent->GetWardId() + "','" + nevent->GetRoomId() + "','"
                    + tmut->ConvIntToString(nevent->GetEventId()) + "','" + nevent->GetDate_Time_Called() + "','"
                    + nevent->GetRoomBedCode() + "')";

            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                if (!dbconn->runRemoveEventInSqLite(nevent))
                    ShowMessage("NAO FOI POSSIVEL REMOVER EVENTO TRATADO!!!", COLOR_BLUE, COLOR_RED);
            }
            //
            break;
            /**
             * Se evente_rauland está com um id e is_cancel for igual a true, seguinifica que há um evento
             * para ser atendido, então etende
             * @param event_rauland
             */
        case 2:// 02 - ATENDIMENTO OU ATENTIDMENTO ESPONTANEO
            ShowMessage("ATENDE UM EVENTO!", COLOR_BLUE, COLOR_PINK);
            /**
             * Aqui valida se o atendimento está sendo feito dentro do tempo
             * informado, caso nao seja, adiciona com time-out
             * @param event_rauland
             */
            if (tmut->ValidAttendTime(nevent->GetDate_Time_Called(), getTimeout_attend()) == true) {
                //Pega a data com time-out
                date_with_timeout = tmut->SumTimeOut(nevent->GetDate_Time_Called(), getTimeout_attend());

                //Monta a query com time-out
                query = "UPDATE data_protocol SET date_time_entered ='" + date_with_timeout
                        + "' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            } else {
                //Monta query sem time-out
                query = "UPDATE data_protocol SET date_time_entered ='" + event->GetDate_Time_Called()
                        + "' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            }

            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                dbconn->runRemoveEventInSqLite(nevent);
            }
            //
            break;
            /**
             * Se evente_rauland está com atendimento porem não foi finalizado,
             * finaliza o evento com ou sem time-out e gera um novo.
             * @param event_rauland
             */
        case 3: // 03 - FINALIZA ATENDIMENTO
            ShowMessage("FINALIZA UM EVENTO E ADICIONA UM NOVO!", COLOR_BLUE, COLOR_PINK);
            /**
             * Aqui valida se esta finalizando o evento dentro do tempo
             * informado, caso nao seja, finaliza com time-out
             * @param event_rauland
             */
            if (tmut->ValidAttendTime(nevent->GetDate_Time_Called(), getTimeout_attend()) == true) {
                //Pega a data com time-out
                date_with_timeout = tmut->SumTimeOut(nevent->GetDate_Time_Called(), getTimeout_attend());

                //Monta query com time-out
                query = "UPDATE data_protocol SET date_time_exited ='" + date_with_timeout
                        + "', status_exited='t' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            } else {
                //Monta query sem time-out
                query = "UPDATE data_protocol SET date_time_exited ='" + nevent->GetDate_Time_Called()
                        + "', status_exited='t' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            }
            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                dbconn->runRemoveEventInSqLite(nevent);
            }
            //Gera novo evento
            query = "INSERT INTO data_protocol (ward_id, room_id, event_id, date_time_called, "
                    "bed_room_code) VALUES ('"
                    + nevent->GetWardId() + "','" + nevent->GetRoomId() + "','"
                    + tmut->ConvIntToString(nevent->GetEventId()) + "','" + nevent->GetDate_Time_Called() + "','"
                    + nevent->GetRoomBedCode() + "')";

            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                dbconn->runRemoveEventInSqLite(nevent);
            }
            //
            break;
            /**
             * Se evente_rauland não foi atendido e recebeu outro evento,
             * faz o atendimento e finaliza o evento com ou sem time-out e gera um novo.
             * @param event_rauland
             */
        case 4:
            //
            ShowMessage("ATENDE E FINALIZA UM EVENTO E ADICIONA UM NOVO!", COLOR_BLUE, COLOR_PINK);
            //
            /**
             * Aqui valida se esta finalizando o evento dentro do tempo
             * informado, caso nao seja, finaliza com time-out
             * @param event_rauland
             */
            if (tmut->ValidAttendTime(nevent->GetDate_Time_Called(), getTimeout_attend()) == true) {
                //Pega a data com time-out
                date_with_timeout = tmut->SumTimeOut(nevent->GetDate_Time_Called(), getTimeout_attend());

                //Monta query com time-out
                query = "UPDATE data_protocol SET date_time_entered ='" + date_with_timeout
                        + "', status_entered = 't', date_time_exited  ='" + date_with_timeout
                        + "', status_exited = 't' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            } else {
                //Monta query sem time-out
                query = "UPDATE data_protocol SET date_time_entered ='" + nevent->GetDate_Time_Called()
                        + "', status_entered = 't', date_time_exited = '" + nevent->GetDate_Time_Called()
                        + "', status_exited = 't' WHERE id = '" + tmut->ConvIntToString(nevent->GetPtlId()) + "'";

                cerr << FG_RED << "[" << __FILE__ << ":" << __LINE__ << "] "
                        << FG_BLUE << "Query...:" << query << END << endl;
            }
            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                dbconn->runRemoveEventInSqLite(nevent);
            }
            //;

            //Gera novo evento
            query = "INSERT INTO data_protocol (ward_id, room_id, event_id, date_time_called, "
                    "bed_room_code) VALUES ('"
                    + nevent->GetWardId() + "','" + nevent->GetRoomId() + "','"
                    + tmut->ConvIntToString(nevent->GetEventId()) + "','" + nevent->GetDate_Time_Called() + "','"
                    + nevent->GetRoomBedCode() + "')";

            //Adiciona na base de dados
            if (dbconn->runQueryInPGree(query)) {
                //Remove o evento da tabela SqLite
                dbconn->runRemoveEventInSqLite(nevent);
            }
            //
            break;
        case 5:
            ShowMessage("REMOVENDO EVENTO DESCATADO!!!", COLOR_BLUE, COLOR_GREEN);
            //Gravar os dados para arquivo
            msg = "\n-------------------------------------------------\n"
                    "\nREMOVENDO EVENTO DA RAULAND DESCARTADO!!!"
                    "\nAla...........: " + nevent->GetWardSigla() +
                    "\nCódigo Quarto.: " + nevent->GetRoomSigla() +
                    "\nEvento Hauland: " + nevent->GetEventMessage() +
                    "\nHora Atual....: " + tmut->getTimeRfc2822() +
                    "\n-------------------------------------------------\n";
            //
            ShowMessage("REMOVENDO EVENTO DESCATADO!!!", COLOR_BLUE, COLOR_GREEN);
            //
            if (!dbconn->runRemoveEventInSqLite(nevent)) {
                ShowMessage("NAO FOI POSSIVEL REMOVER EVENTO TRATADO!!!", COLOR_BLUE, COLOR_RED);
            }

            //Pasta onde serar gravado o arquivo
            dirfl->setFolder_write("/Logs/Rld/Rm/");
            //   
            //
            dirfl->CreateLogFile("LOGRLDRM", msg);
                        //Aguarda um segundo
            //tmut->SleepSeg(100);
            //
            if (!dbconn->runRemoveEventInSqLite(nevent)) {
                ShowMessage("NAO FOI POSSIVEL REMOVER EVENTO TRATADO!!!", COLOR_BLUE, COLOR_RED);
            }
            break;
        default://se o evento for maior que 40, entra aqui
            break;
    }

}

/**
 * Metodo responsavel por pegar a opção
 * para aplicar para o evento.
 * @param nevent
 * @return 
 */
int ThreadMngEventRld::getOptionForApply(Event *nevent) {

    ShowMessage("EVENTO PESQUISADO......: ID: "
            + tmut->ConvLongToString(nevent->GetPtlId()) + " DATA ENTRA: "
            + nevent->GetDate_Time_Entered() + " DATA SAIDA: "
            + nevent->GetDate_Time_Exited(), COLOR_BLUE, COLOR_PINK);

    /**
     * Se evente_rauland vim sem um id, e se o evento nao for 
     * de cancelamento, é porque não tem evento para
     * ser atendido, então entra para fazer a inclusão
     * @param event_rauland
     */
    if (nevent->GetPtlId() == 0 && !nevent->IsEventCancel()) {
        //
        ShowMessage("ADD UM NOVO EVENTO!", COLOR_BLUE, COLOR_PINK);
        //
        return 1; //Para novo evento
    }/**
         * TEM ID & ER ATENDIMENTO = ATENDER
         * Se não tiver atendimento e for um cancelamento
         * retorna 2 para atendimento.
         * @param nevent
         * @return 
         */
    else if (nevent->GetDate_Time_Entered().empty() && nevent->IsEventCancel()) {
        //
        ShowMessage("ATENDE UM EVENTO!", COLOR_BLUE, COLOR_PINK);
        //
        return 2;
    }/**
         * Descarta um evento de atendimento, quando nao tem evento para ser 
         * atendido.
         * @param nevent
         * @return 
         */
    else if (!nevent->GetDate_Time_Entered().empty() && nevent->IsEventCancel()) {
        //
        ShowMessage("DESCARTANDO ATENDIMENTO PARA EVENTO POR NAO EXISTIR!", COLOR_BLUE, COLOR_PINK);
        //
        return 5; //Para descarta cancelamento sem atendimento   
    }/**
         * Atende um evento anterior da mesma Ala, 
         * e adiciona um novo.
         * @param nevent
         * @return 
         */
    else if (!nevent->GetDate_Time_Entered().empty() && nevent->GetDate_Time_Exited().empty()) {
        //
        ShowMessage("FINALIZA UM EVENTO E ADICIONA UM NOVO!", COLOR_BLUE, COLOR_PINK);
        //
        return 3;
    }/**
         * Atende e Finaliza um evento anterior da mesma Ala,
         * e adiciona um novo.
         * @param nevent
         * @return 
         */
    else if (nevent->GetDate_Time_Entered().empty() && nevent->GetDate_Time_Exited().empty()) {
        //
        ShowMessage("ATENDE E FINALIZA UM EVENTO E ADICIONA UM NOVO!", COLOR_BLUE, COLOR_PINK);
        //
        return 4;
    }

    //Descarta com a opcao 5
    return 5;
}